package analysis;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.io.File;
import java.util.HashSet;
import java.util.List;

import model.Element;
import model.SysClass;
import model.SysMethod;
import model.SysPackage;
import model.SysRoot;

import org.junit.Test;


public class MethodAnalysisTest {


	String pathToP1 = "."+File.separator+"test-programs"+File.separator+
			"PackInPack_lotsOfClassesInSinglePack"+File.separator+"bin";
	String pathToP2 = "."+File.separator+"test-programs"+File.separator+
			"DefaultPackage"+File.separator+"bin";
	String pathToHashKnowledgement = pathToP1 +File.separator+"pack1"+File.separator+
			"rapidinho"+File.separator+"HashKnowlegment.class";
	String pathToRecursion = "."+File.separator+"test-programs"+File.separator+
			"recursion"+File.separator+"bin";
	String pathToHello = pathToRecursion + File.separator+"hello"+File.separator+"Hello";



	@Test
	public void duplicatedCalls(){
		String code = "128: invokespecial java.lang.String.<init>"+"\n" +
				"130: invokestatic java.lang.String.<init>"+"\n" +
				"132: invokespecial java.lang.String.<init>"+"\n" +
				"134: invokevirtual java.lang.String.<init>";
		HashSet<String> mustReturn = new HashSet<String>();
		mustReturn.add("invokespecial java.lang.String.<init>");
		mustReturn.add("invokestatic java.lang.String.<init>");
		mustReturn.add("invokevirtual java.lang.String.<init>");

		List<String> methodCalls= MethodAnalysis.getMethodCalls(code);
		assertTrue(mustReturn.containsAll(methodCalls) && methodCalls.containsAll(mustReturn));
		System.out.println(methodCalls);
	}

	/*
	@Test
	public void findPathToMethod(){
		String pathToFind = "ict.sjc.bcc.ic.EmgenhariaDeSoftware.SysGraph4AJ.<init>";
		SysPackage unifesp = new SysPackage("unifesp");
		SysPackage ict = new SysPackage("ict");
		SysClass ictClass = new SysClass("ict");
		SysPackage sjc = new SysPackage("sjc");
		SysPackage bcc = new SysPackage("bcc");
		SysClass bccClass = new SysClass("bcc");

		sjc.add(bcc);
		sjc.add(bccClass);
		ict.add(sjc);
		unifesp.add(ict);
		unifesp.add(ictClass);
		//model created
		LinkedList<Element> ll = new LinkedList<Element>(); //list that would be returned
		ll.add(bcc);
		ll.add(bccClass);
		ll.add(sjc);
		ll.add(ict);
		ll.add(ictClass);
		ll.add(unifesp);

		LinkedList<Element> autoLL= null;
		try{
			autoLL = Old_MethodAnalysis.findOptions(unifesp, pathToFind);
		} catch (RuntimeException r){
			System.out.println("Checked RuntimeException");
			return;
		}
		boolean equals = true;
		if(ll.size()!=autoLL.size()) equals=false;
		int i=0;
		while(equals==true && i<ll.size()){
			if(!ll.get(i).equals(autoLL.get(i))) equals=false;
			i++;
		}
		assertTrue(equals);
		System.out.println(autoLL);
		System.out.println(ll);

	}*/

	@Test
	public void methodNotFound(){
		SysMethod m = new SysMethod(false, "<init>", "V", "public");
		Exception p=null;
		String signature="";
		try{
			MethodAnalysis.tryOption(m, "anyStringInHere", signature, new SysRoot());  
		}catch(PathNotFoundException e){ 
			p=e; 
		}
		assertTrue(p instanceof PathNotFoundException);
	}

	@Test
	public void selfReturn(){
		SysMethod m = new SysMethod(false, "<init>", "V", "public");
		Element p=null;
		String signature="";
		try{
			p = MethodAnalysis.tryOption(m, "", signature, new SysRoot());  
		}catch(PathNotFoundException e){ /*...*/ }
		assertTrue(p instanceof SysMethod);
	}


	/*make a new .class file to run the test
	@Test
	public void lastClass_ReturnAMethod(){
		SysRoot r = new SysRoot(pathToP1);
		SysPackage p1 = new SysPackage("pack1");
		SysPackage p11 = new SysPackage("rapidinho");
		SysClass c = new SysClass("HashKnowlegment");


		r.add(p1);
		p1.add(p11);
		p11.add(c);

		Element o=null;
		String signature="";
		try{
			o = MethodAnalysis.tryOption(c, "<init>", signature, r);  //needs to implement
		}catch(PathNotFoundException e){
			assertFalse(true);
		}
		assertTrue(o instanceof SysMethod);//just ensures that "o" is not null
		assertTrue(o.getName().equals("<init>"));
	}



	@Test
	public void returnFatherPackage(){
		System.out.println("return father package test...");
		SysRoot r = new SysRoot(pathToP1);
		SysPackage p1 = new SysPackage("pack1");
		r.add(p1);

		String pathToFind = "rapidinho.HashKnowlegment.<init>";

		Element o=null;
		String signature="";
		try{
			o = MethodAnalysis.tryOption(p1, pathToFind, signature, r);  //needs to implement
		}catch(PathNotFoundException e){ 
			System.out.println("PathNotFoundException...");
			assertTrue(false);
		}catch (NullPointerException npe){
			System.out.println("NullPointerException...");
			npe.printStackTrace();
			JOptionPane.showMessageDialog(null, "NullPointerException", "Err", JOptionPane.ERROR_MESSAGE);
		}

		boolean right = true;
		//JOptionPane.showMessageDialog(null, o!=null?o:"null");
		assertTrue(o instanceof SysPackage);
		assertTrue(o.getName().equals("rapidinho"));
		for(SysClass c: ((SysPackage)o).getClasses()){
			System.out.println(c.getName());
			if(!c.getName().equals("HashKnowlegment")) right = false;
			for(SysMethod m: c.getMethods()){
				System.out.println(m.getName());
				if(!m.getName().equals("<init>")) right = false;
			}
		}

		assertTrue(right);

	}
	 */


	@Test
	public void addingElementIntoElement(){
		SysPackage p = new SysPackage("package");
		SysClass c = new SysClass("Class");
		SysMethod m = new SysMethod(false,null,null,null);
		assertTrue(MethodAnalysis.addElementToElement_notDependency(p,p));
		assertTrue(MethodAnalysis.addElementToElement_notDependency(p,c));
		assertFalse(MethodAnalysis.addElementToElement_notDependency(p,m));
		assertFalse(MethodAnalysis.addElementToElement_notDependency(c,p));
		assertTrue(MethodAnalysis.addElementToElement_notDependency(c,c));
		assertTrue(MethodAnalysis.addElementToElement_notDependency(c,m));
		assertFalse(MethodAnalysis.addElementToElement_notDependency(m,p));
		assertFalse(MethodAnalysis.addElementToElement_notDependency(m,c));
		assertFalse(MethodAnalysis.addElementToElement_notDependency(m,m));
		assertFalse(MethodAnalysis.addElementToElement_notDependency(p, null));
	}


	//	@Test
	//	public void testFindOptions_SysMethod(){
	//		SysRoot r = SysAnalysis.initialModel(pathToRecursion);
	//		SysPackage hello = r.getPackages().iterator().next();
	//		SysClass Hello = null;
	//		for(SysClass clzz : hello.getClasses()){
	//			if(clzz.getName().equals("Hello")){
	//				Hello=clzz;
	//				break;
	//			}
	//		}
	//		ClassAnalysis.analyseClass(Hello, r);
	//		HashSet<SysMethod> classes = Hello.getMethods();
	//		Iterator<SysMethod> i = classes.iterator();
	//		SysMethod method1 =null;
	//		while(i.hasNext()){
	//			SysMethod m = i.next();
	//			MethodAnalysis.analyseMethod(m, r);
	//			if(m.getName().equals("method1")) method1=m;
	//		}
	//		LinkedList<Element> lle = MethodAnalysis.findOptions(hello, Hello.getName()+".method1 ()V");
	//		//boolean b = true;
	//		LinkedList<Element> mylle = new LinkedList<Element>();
	//		mylle.add(method1);
	//		mylle.add(Hello);
	//		mylle.add(hello);
	//		System.out.println(mylle.toString());
	//		System.out.println(lle.toString());
	//		assertTrue(hello.getFullyQualifiedName().equals("hello"));
	//		assertTrue(Hello.getName().equals("Hello"));
	//		assertTrue(method1.getName().equals("method1"));
	//		assertTrue(method1.getParameters().iterator().next().equals("I"));
	//		assertTrue(lle.toString().equals(mylle.toString()));
	//	}
	//	
	//	@Test
	//	public void testDependency(){
	//		SysRoot r = SysAnalysis.initialModel(pathToRecursion);
	//		SysPackage hello = r.getPackages().iterator().next();
	//		SysClass Hello = null;
	//		for(SysClass clzz : hello.getClasses()){
	//			if(clzz.getName().equals("Hello")){
	//				Hello=clzz;
	//				break;
	//			}
	//		}
	//		ClassAnalysis.analyseClass(Hello, r);
	//		HashSet<SysMethod> classes = Hello.getMethods();
	//		Iterator<SysMethod> i = classes.iterator();
	//		SysMethod method1 =null;
	//		while(i.hasNext()){
	//			SysMethod m = i.next();
	//			MethodAnalysis.analyseMethod(m, r);
	//			if(m.getName().equals("method1")) method1=m;
	//		}
	//		MethodAnalysis.analyseMethod(method1, r);
	//		assertTrue(method1.getCalls().size()==1);
	//		assertTrue(method1.getCalls().iterator().next().equals(method1));
	//	}
	//	
	//	@Test
	//	public void testDependency2(){
	//		SysRoot r = SysAnalysis.initialModel(pathToRecursion);
	//		SysPackage hello = r.getPackages().iterator().next();
	//		SysClass Hello = null;
	//		SysClass Hello1 = null;
	//		for(SysClass clzz : hello.getClasses()){
	//			if(clzz.getName().equals("Hello")){
	//				Hello=clzz;
	//			}
	//			if(clzz.getName().equals("Hello1")){
	//				Hello1=clzz;
	//			}
	//			
	//		}
	//		ClassAnalysis.analyseClass(Hello, r);
	//		ClassAnalysis.analyseClass(Hello1, r);
	//		SysMethod init = Hello1.getMethods().iterator().next();
	//		HashSet<SysMethod> classes = Hello.getMethods();
	//		Iterator<SysMethod> i = classes.iterator();
	//		SysMethod method1 =null;
	//		SysMethod main =null;
	//		
	//		while(i.hasNext()){
	//			SysMethod m = i.next();
	//			MethodAnalysis.analyseMethod(m, r);
	//			if(m.getName().equals("method1")) method1=m;
	//			if(m.getName().equals("main")) main=m;
	//		}
	//		MethodAnalysis.analyseMethod(main, r);
	//		assertTrue(main.getCalls().size()==1);
	//		assertTrue(main.getCalls().iterator().next().equals(init));
	//	}
}
